home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * MAKEGUSH.C
- *
- * (Simon Hern, 1994)
- *
- * Generate some Gush data for the Bouncing Planets demo
- *
- * Asks for desired planet radius and orientation (as two rotations)
- *
- * The Gush is written to the file GUSH.DAT
- * The data is in compiled form, i.e., executable code
- * Four interlaced Mode X slices are used, with vectors to them at
- * data offsets 1, 4, 7, and 10
- * The first byte of the gush is the planet's radius
- * The slices 'return far' on completion
- * Gush assumes that: ES:DI is the top left corner of the image on screen
- * DS:SI is the start of the expanded Xion array
- * Gush data cannot be longer than 64k (size depends on RHO value)
- *
- * GUSHCODE.ASM provides an interface to gush data for the C language
- *
- */
-
-
- #include <math.h>
- #include <stdio.h>
- #include <alloc.h>
-
- /* XLib v06 */
- #include <xfileio.h>
-
- /* Local definitions (notably RHO: the surface resolution) */
- #include "planet.h"
-
-
-
- /* Viewing distance for perspective */
- #define DIST 2000.0
-
- /* Largest planet radius possible (restricted by segment size) */
- #define MAX_RADIUS 64
-
- /* Value to mark unused parts of grid (both xm and ym values) */
- #define NOT_USED 255
-
- /* File to write data to */
- #define GUSH_FILE "GUSH.DAT"
-
- /* Screen width (a quarter of this according to Mode X) */
- #define SCR_WIDTH 320
-
- /* Machine code */
- #define JMP 0xE9 /* 'jump near relative' */
- #define ADD_DI_B1 0x83 /* 'add byte to DI' byte 1 */
- #define ADD_DI_B2 0xC7 /* 'add byte to DI' byte 2 */
- #define ADD_DI_W1 0x81 /* 'add word to DI' byte 1 */
- #define ADD_DI_W2 0xC7 /* 'add word to DI' byte 2 */
- #define STOSB 0xAA /* 'store AL at DI and inc DI' */
- #define STOSW 0xAB /* 'store AX at DI and inc DI' */
- #define MOV_AL_1 0x8A /* 'get AL relative to SI' byte 1 */
- #define MOV_AL_2 0x84 /* 'get AL relative to SI' byte 2 */
- #define MOV_AH_1 0x8A /* 'get AH relative to SI' byte 1 */
- #define MOV_AH_2 0xA4 /* 'get AH relative to SI' byte 2 */
- #define RETF 0xCB /* 'far return' */
-
-
-
- /* Structure for values to be stored at each point in the grid */
- typedef struct {
- unsigned char xm;
- unsigned char ym; /* 'char' suitable for RHO up to 128 */
- } GridVals;
-
-
-
- /* Save data from 'far' array (up to 65535 bytes) */
- int far_save(char * fname, char far * data, unsigned len);
-
-
-
- void main() {
-
-
- /* The Grid: Image of the planet; results of calculations (Square Gush) */
- GridVals grid[2*MAX_RADIUS][2*MAX_RADIUS];
-
- /* The Gush: Compiled code for drawing a planet */
- unsigned char far * gush;
-
-
-
- /* Stage 1 variables */
-
- int radius; /* Visible radius of planet (in pixels) */
- double r; /* Actual radius of planet */
-
- int theta, phi; /* Rotation angles */
- double cth, sth, cph, sph; /* cos and sin of theta and phi */
-
- unsigned gridx, gridy; /* Current position in grid */
- double xs, ys; /* Screen coords relative to screen centre */
- double xp, yp, zp; /* 3D coords of point on planet surface */
- double xt, yt, zt; /* 3D coords after twist and turn */
- int xm, ym; /* Map coords */
-
- double zs, k, alpha, beta, w; /* Temporary values */
-
-
-
- /* Stage 2 variables */
-
- unsigned int i; /* Index into gush object */
- unsigned int start; /* Start of current slice of gush */
- int slice; /* Slices 0-3 for Mode X convenience */
- unsigned int blanks; /* Number of pixels to hop over */
- int got_one; /* Flags presence of first half of a pair */
- unsigned int source; /* Address to grab value from */
-
-
-
- /* Request radius and angles */
-
- printf("\nPlanet radius (max %d): ", MAX_RADIUS);
- scanf("%d", &radius);
- printf("\nBackward tilt in degrees (phi): ");
- scanf("%d", &phi);
- printf("\nClockwise turn in degrees (theta): ");
- scanf("%d", &theta);
-
- /* The radius can't be too large or the gush overflows the 64k barrier */
- if ( radius > MAX_RADIUS || radius < 4 ) radius = MAX_RADIUS / 2;
- /* I'm insisting that the radius be a multiple of 4. There's no real */
- /* reason for this as far as I can see, it's just that the one time */
- /* I tried an odd radius the program glitched. So there. */
- radius = radius & 0xFFFC;
-
- phi = phi % 360;
- theta = theta % 360;
- printf("\nRadius = %d, ", radius);
- printf("Phi = %d, Theta = %d\n\n", phi, theta);
-
- r = DIST * radius / sqrt( DIST*DIST + radius*radius );
- cth = cos( (double)theta * PI/180 );
- sth = sin( (double)theta * PI/180 );
- cph = cos( (double)phi * PI/180 );
- sph = sin( (double)phi * PI/180 );
-
-
-
- /* Stage 1: Fill in the grid */
- /* (Do lots of sums. Grid points either hold results or are left blank) */
-
- printf("Calculating %d lines\n", 2*radius);
-
- for( gridy=0, ys=radius-0.5 ; gridy < 2*radius ; gridy++, ys-- ) {
- for( gridx=0, xs=0.5-radius ; gridx < 2*radius ; gridx++, xs++ ) {
-
- zs = sqrt( xs*xs + ys*ys );
- if ( zs > radius ) {
- /* Not a point in the planet image */
- xm = NOT_USED;
- ym = NOT_USED;
- } else {
-
- k = ( DIST*DIST -
- sqrt( DIST*DIST*( r*r - zs*zs ) + r*r*zs*zs ) )
- / ( DIST*DIST + zs*zs );
- yp = k * ys;
- xp = k * xs;
- zp = sqrt( r*r - xp*xp - yp*yp );
-
- xt = xp*cth - yp*sth*cph + zp*sth*sph;
- yt = xp*sth + yp*cth*cph - zp*cth*sph;
- zt = yp*sph + zp*cph;
-
- if ( yt > r ) yt = r;
- if ( yt < -r ) yt = -r;
- w = sqrt( r*r - yt*yt );
- alpha = acos( yt/r );
-
- if ( xt > w ) xt = w;
- if ( xt < -w ) xt = -w;
- beta = acos( - xt/w );
-
- xm = (int) ( beta * RHO/PI );
- if ( xm == RHO ) xm--;
- ym = (int) ( alpha * RHO/PI );
- if ( ym == RHO ) ym--;
-
- if ( zt < 0 ) xm = 2*RHO - 1 - xm;
-
- }
-
- grid[gridy][gridx].xm = (unsigned char)xm;
- grid[gridy][gridx].ym = (unsigned char)ym;
- }
-
- printf(" Line: %d\r", gridy);
- }
-
-
-
- /* Stage 2: Compile grid to gush */
- /* (Move through the grid, generating point plotting machine code) */
-
- printf("Compiling data\n");
-
- gush = (unsigned char far *)farmalloc(65535L);
- if ( gush == NULL ) {
- printf("ERROR: Run out of memory\n");
- exit(1);
- }
-
- /* First byte is the radius */
- gush[0] = (unsigned char)radius;
-
- /* Then 12 bytes of vectors to slices */
- gush[1] = gush[4] = gush[7] = gush[10] = JMP;
-
- start = 13; /* After vectors */
- for ( slice = 0 ; slice < 4 ; slice++ ) {
-
- i = start;
- blanks = 0;
- got_one = 0;
- for ( gridy = 0 ; gridy < 2*radius ; gridy++ ) {
- for ( gridx = slice ; gridx < 2*radius ; gridx+=4 ) {
-
- xm = grid[gridy][gridx].xm;
- ym = grid[gridy][gridx].ym;
-
- if ( xm == NOT_USED && ym == NOT_USED ) {
-
- /* Skip over this point */
- blanks++;
-
- } else {
-
- if ( blanks ) {
- /* Any points outstanding? */
- if ( got_one ) {
- gush[i++] = STOSB;
- got_one = 0;
- }
-
- /* Move screen pointer on some */
- if ( blanks <= 127 ) {
- /* Add byte value */
- gush[i++] = ADD_DI_B1;
- gush[i++] = ADD_DI_B2;
- gush[i++] = blanks;
- } else {
- /* Add word value */
- gush[i++] = ADD_DI_W1;
- gush[i++] = ADD_DI_W2;
- gush[i++] = blanks & 0xFF;
- gush[i++] = blanks >> 8;
- }
- blanks = 0;
- }
-
- /* Calculate source address */
- source = xm + 4*RHO*(unsigned)ym;
-
- /* And write the code */
- if ( got_one ) {
- /* Second half of a pair */
- gush[i++] = MOV_AH_1;
- gush[i++] = MOV_AH_2;
- gush[i++] = source & 0xFF;
- gush[i++] = source >> 8;
- gush[i++] = STOSW;
- got_one = 0;
- } else {
- /* First half of a pair */
- gush[i++] = MOV_AL_1;
- gush[i++] = MOV_AL_2;
- gush[i++] = source & 0xFF;
- gush[i++] = source >> 8;
- got_one = 1;
- }
-
- }
-
- /* Check i not about to got out of bounds */
- if ( i > 65500 ) {
- printf("Sorry, run out of space for gush\n"
- "Try a smaller planet radius\n");
- exit(0);
- }
-
- } /* for ( gridx ) */
-
- /* Around edge of screen */
- blanks += ( SCR_WIDTH - 2*radius ) / 4;
-
- } /* for ( gridy ) */
-
- /* Just one left? */
- if ( got_one ) gush[i++] = STOSB;
-
- gush[i++] = RETF;
-
- /* Line up vectors */
- gush[3*slice+2] = ( start - slice*3 - 4 ) & 0xFF;
- gush[3*slice+3] = ( start - slice*3 - 4 ) >> 8;
- start = i;
-
- } /* for ( slice ) */
-
-
-
- /* Output gush to file */
- if ( ! far_save(GUSH_FILE, gush, i) ) {
- printf("ERROR: Cannot create %s\n", GUSH_FILE);
- exit(1);
- }
-
- printf("\nData saved to %s, length %.0f bytes\n", GUSH_FILE, (double)i);
-
- farfree((void far *)gush);
-
- }
-
-
-
- /* Function to save data from 'far' array (up to 65535 bytes) */
-
- int far_save(char * fname, char far * data, unsigned len) {
- int fout;
-
- fout = f_open(fname, F_WRONLY);
- if ( fout == FILE_ERR ) return 0;
-
- f_writefar(fout, data, len);
-
- f_close(fout);
- return 1;
- }
-
-